iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 14
1
Modern Web

JavaScript基本功修煉系列 第 14

JavaScript基本功修練:Day14 - 陣列高階函數練習之Codewars刷題(II)

  • 分享至 

  • xImage
  •  

承接昨天的練習,今天再來看看Codewars collection這裏的三條題目(第4,5,7題)。整理一下自己的解法之外,也藉此機會學習別人的解法。因為篇幅問題,所以不會貼整條問題,有興趣的朋友可以到連結查看~

題目4

Coding Meetup #4 - Higher-Order Functions Series - Find the first Python developer

題目概要:

  • 找出第一個寫Python的開發者,按以下格式回傳結果:
    firstName, country
  • 如無Python開發者,就回傳There will be no Python developers
var list1 = [
  { firstName: 'Mark', lastName: 'G.', country: 'Scotland', continent: 'Europe', age: 22, language: 'JavaScript' },
  { firstName: 'Victoria', lastName: 'T.', country: 'Puerto Rico', continent: 'Americas', age: 30, language: 'Python' },
  { firstName: 'Emma', lastName: 'B.', country: 'Norway', continent: 'Europe', age: 19, language: 'Clojure' }
];

我的解法

function getFirstPython(list) {
// Thank you for checking out my kata :)
const result = list.filter( ({language}) => language === 'Python')
return result.length > 0 ? `${result[0].firstName}, ${result[0].country}` : `There will be no Python developers`
}

這題難度不高,所以很直覺就用filterlength的方法去寫,但submit答案之後又發現一些更合適的寫法。

別人的解法

第1個解法:

function getFirstPython(list) {
  const dev = list.find(x => x.language === "Python")
  return dev ? `${dev.firstName}, ${dev.country}` : "There will be no Python developers"
}

突然發現自己竟然沒有想到用find的方法!因為題目要求只找出第一個寫Python的開發者就可以了,所以這裏非常適合用find

第2個解法:

const getFirstPython = list =>
  (val => val ? `${val.firstName}, ${val.country}` : `There will be no Python developers`)
  (list.find(val => val.language === `Python`));

這個解法我看了幾次都看不懂,之後看看原作者在他的答案下的comment,提到立即函式(IIFE)的MDN連結,我才明白他在用立即函式的方法簡寫第一個解法。他把用find找出來的結果當作参數,傳進立即函式裏面去做判斷。

第3個解法:

function getFirstPython(list) {
// Thank you for checking out my kata :)
const result = list.filter( ({language}) => language === 'Python')[0]
return result ? `${result.firstName}, ${result.country}` : `There will be no Python developers`
}

這個解法是我看完另一個網友的寫法,再去簡寫我的寫法。直接在filter建立的陣列裏指定第一個元素,之後拿它去做判斷。如果根本沒有Python開發者的話,result會是undefinedundefined是falsy,這便會回傳沒有Python開發者的那句字串。這樣就不用拿length > 0去做比對了。

題目5

Coding Meetup #5 - Higher-Order Functions Series - Prepare the count of languages

題目概要:回傳一個物件,裏面會顯示有多少個開發者在用某個程式語言。
例如這堆資料中:

var list1 = [
  { firstName: 'Noah', lastName: 'M.', country: 'Switzerland', continent: 'Europe', age: 19, language: 'C' },
  { firstName: 'Anna', lastName: 'R.', country: 'Liechtenstein', continent: 'Europe', age: 52, language: 'JavaScript' },
  { firstName: 'Ramon', lastName: 'R.', country: 'Paraguay', continent: 'Americas', age: 29, language: 'Ruby' },
  { firstName: 'George', lastName: 'B.', country: 'England', continent: 'Europe', age: 81, language: 'C' },
];

這裏要回傳:

{ C: 2, JavaScript: 1, Ruby: 1 }

我的解法

function countLanguages(list) {
// thank you for checking out the Coding Meetup kata :)

//建立一個放著全部開發者寫的程式語言的陣列
const allList = list.map( (dev) => dev.language)
//建立一個程式語言不重覆的陣列
const uniqueList = allList.filter( (dev,index)=> allList.indexOf(dev) === index)
const obj = {}

//建立一個物件:{uniqueList的元素 : 以目前uniqueList裏被迭代的語言為篩選條件,找尋在allList陣列中與篩選條件相同的語言,放列一個陣列裏,並求它的長度}
for(i=0; i<uniqueList.length; i++){
   obj[uniqueList[i]] = allList.filter( (language) => language === uniqueList[i]).length
}
return obj 
}

這題自己的確花了點時間去想,簡單講我的思路就是建立兩個陣列,一個是有重覆元素的陣列(allList),一個是不重覆元素的陣列(uniqueList)。在uniqueList陣列裏的所有元素,就是obj所有的鍵(key)。

而這些鍵對應的值(value)呢?在每一次跑uniqueList的元素時,該元素會成為篩選條件,讓我在allList裏找出與篩選條件一樣的程式語言,並放到一個新陣列裏。例如跑到"C"時,因為有2個開發者寫C,所以會得出["C","C"]這個陣列,跑到"JavaScript"時,會得出["JavaScript"],如此類推。而這些陣列的length,就代表人數,也就是鍵對應的值。

但自己這樣寫真的是太累贅了,還是看看別人的解法來學習吧。

別人的解法

第1個解法:

function countLanguages(list){
    const count = {}
    list.forEach( (dev)=> count[dev.language] = (count[dev.language] || 0)+1)
    return count
}

一開始看不懂,看懂之後就不得了~~ 果然是最佳解答!在forEach函式裏,先判斷count物件裏面有沒有該程式語言的屬性,如沒有,就預設是0,之後再+1,例如第一次跑forEach時,就會變成{C:(0+1)},在跑最後一次時,就會變成{C:(1+1)}

第2個解法:

function countLanguages(list) {
    var r = {};
    list.forEach(x => {
        let p = [x.language];
        r.hasOwnProperty(p) ? r[p] ++ : r[p] = 1;
    });
    return r;
}

這裏的解法與第1個解法的思路很相似,差異是這裏用hasOwnProperty()的方法,而非短路求值||的方法,去檢查物件裏是否已經有某個程式語言屬性,以及設定預設值。如果已有屬性,就在該屬性值+1,如無,就預設值為1。

題目7

Coding Meetup #7 - Higher-Order Functions Series - Find the most senior developer

題目6比較答案比較直接,而且大家答法都很相似,所以就直接跳到討論題目7~

題目概要:回傳一個陣列,裏面放有年紀最大的開發者資料,如年齡相同,則按原本陣列的顯示次序來顯示。

例如以下這堆資料:

var list1 = [
  { firstName: 'Gabriel', lastName: 'X.', country: 'Monaco', continent: 'Europe', age: 49, language: 'PHP' },
  { firstName: 'Odval', lastName: 'F.', country: 'Mongolia', continent: 'Asia', age: 38, language: 'Python' },
  { firstName: 'Emilija', lastName: 'S.', country: 'Lithuania', continent: 'Europe', age: 19, language: 'Python' },
  { firstName: 'Sou', lastName: 'B.', country: 'Japan', continent: 'Asia', age: 49, language: 'PHP' },
];

我要回傳的結果是:

[
  { firstName: 'Gabriel', lastName: 'X.', country: 'Monaco', continent: 'Europe', age: 49, language: 'PHP' },
  { firstName: 'Sou', lastName: 'B.', country: 'Japan', continent: 'Asia', age: 49, language: 'PHP' },
]

我的解法

function findSenior(list) {
// thank you for checking out the Coding Meetup kata :)
const oldest = list.reduce( (a,b) => a.age >= b.age ? a : b);
return list.filter( dev => dev.age === oldest.age)
}

這題其實都比較簡單,要找出年紀最大的開發者,意思就是找出age屬性值最大的物件。這裏我用reduce的方法,比對每個物件的age屬性值,如果找到較大的值,就返回那一個物件,並在下一次比較時,用那一個物件的age屬性與目前被迭代的物件的age屬性比較,整個reduce函式最後會回傳age屬性值最大的物件。之後再用filter方法建立陣列,放有與最大年紀相同的物件。

別人的解法

function findSenior(list) {
  var maxAge = Math.max(...list.map(person => person.age));
  return list.filter(person => person.age === maxAge);
}

看完這個解法後,突然又想起自己忘記了Math.max這個超級好用的方法!先用map的函式,集合所有age屬性值在一個陣列裏,用展開運算子攤開所有在陣列中的數字,之後再用Math.max的方法找出最大數字。最後的做法就如我的解法一樣了。

總結

雖然有些寫法好像真的比較簡潔,但個人覺得過於追求簡潔性時也可能會降低了程式碼的可讀性(?),使之後除錯時會更困難。除此之外,在刷題的過程中,看到別人的解法,除了比較哪個寫得最短之外,也需要思考一下別人的思路,以及他的思路與自己的思路的相異之處,希望這樣的訓練會使自己更懂得靈活去做不同方法,也更懂得了解別人的程式碼。


上一篇
JavaScript基本功修練:Day13 - 陣列高階函數練習之Codewars刷題(I)
下一篇
JavaScript基本功修練:Day15 - 解構賦值的概念與應用
系列文
JavaScript基本功修煉31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言